﻿using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Data.Sql;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms; // for toolstripProgressBar
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; // for TypeConverter
using Gibbed.IO;
using Gibbed.MassEffect3.PackageUnpack;
using AmaroK86.ImageFormat;
using AmaroK86.MassEffect3.PCCHandler;
using AmaroK86.MassEffect3.PCC;
using AmaroK86.MassEffect3.ZlibBlock;

namespace AmaroK86.MassEffect3.Texture
{
    public class TextureInfoCollection : KeyedCollection<string, TextureInfo>
    {
        public TextureInfoCollection() : base() { }
        protected override string GetKeyForItem(TextureInfo item)
        {
            return item.id;
        }
    }

    public class TextureDataCollection : KeyedCollection<string, TextureData>
    {
        public TextureDataCollection() : base() { }
        protected override string GetKeyForItem(TextureData item)
        {
            return item.id;
        }
    }

    public class TextureInfo
    {
        public string id = "";
        public string name = "unknown";
        public string format = "";
        public string material = "";
        public ImageSize size = null;
        public ImageSize originalSize = null;
        public int mipTailBaseIdx = 0;
        public string mipGenSettings = "";
        public string compressionSettings = "";
        public float adjustSaturation = 0;
        public int internalFormatLODBias = 0;
        public string LODGroup = "";
        public int LODGroupVal = 0;
        public long LODGroupOffset = 0;
        public string tfcFileName = "";
        public SortedList<string, long> pccFileList = new SortedList<string, long>();
        public TextureDataCollection TexDataList = new TextureDataCollection();
    }

    public class TextureData
    {
        public string id = "";
        public storage fileStore;
        public long arcOffset;
        public long pccOffset;
        public ImageSize texSize;
        public int compressSize;
        public int uncompressSize;

        public TextureData(storage fileStore, ImageSize tSize, long arcOffset, long pccOffset, int compressSize, int uncompressSize)
        {
            this.fileStore = fileStore;
            this.arcOffset = arcOffset;
            this.pccOffset = pccOffset;
            this.texSize = tSize;
            this.compressSize = compressSize;
            this.uncompressSize = uncompressSize;
        }
    }

    public enum storage:short
    {
        local   = 0x00,
        dlc     = 0x01,
        archive = 0x03,
        unused  = 0x21
    }

    public class TextureDatabase
    {
        public TextureInfoCollection textureList = null;
        public int Count { get { return (textureList == null) ? 0 : textureList.Count; } }
        public string currentGamePath = null;
        public string sqlDBName = "me3expdb.sqlite";
        public SQLiteDatabase sqlDB;

        public List<string> defaultPathList = new List<string>();

        public TextureDatabase()
        {
            defaultPathList.Add(@"C:\Program Files\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole");
            defaultPathList.Add(@"C:\Program Files (x86)\Origin Games\Mass Effect 3\BIOGame\CookedPCConsole");
            if (!File.Exists(sqlDBName))
                throw new FileNotFoundException("SQL Database isn't found.");
            sqlDB = new SQLiteDatabase(sqlDBName);
        }

        // function that check and recover file path of pcc and tfc archive
        public bool checkDBPaths(OpenFileDialog openFileDialog)
        {
            string queryUpdatePaths = "";
            string queryPcc = "SELECT File_Name FROM tbl_Pcc;";
            DataTable tablePcc = sqlDB.GetDataTable(queryPcc);
            foreach (DataRow pccNameRow in tablePcc.Rows)
            {
                string pccPath = ToString(pccNameRow,"File_Name");
                string pccFileName = Path.GetFileName(pccPath);
                string pccDirectory = Path.GetDirectoryName(pccPath);
                string newPath = null;
                if(File.Exists(pccPath)) // if file already exists then jump to next
                    continue;
                foreach(string defaultPath in defaultPathList) // check if file is present inside default path list
                {
                    if(File.Exists(defaultPath + "\\" + pccFileName))
                    {
                        newPath = defaultPath + "\\" + pccFileName;
                        break;
                    }
                }
                if(newPath == null) // if file not found inside default path list
                {
                    openFileDialog.Title = "Select the file " + pccFileName;
                    openFileDialog.FileName = pccFileName;
                    openFileDialog.Filter = pccFileName + "|" + pccFileName;
                    if(openFileDialog.ShowDialog() == DialogResult.OK) // directly search the file
                    {
                        newPath = openFileDialog.FileName;
                        defaultPathList.Add(Path.GetDirectoryName(openFileDialog.FileName));
                    }
                    else // if user cancel, then exit the function
                        return false;
                }
                queryUpdatePaths += @"UPDATE tbl_Pcc SET File_Name = '" + newPath + "' WHERE File_Name = '" + pccPath + "';";
            }
            sqlDB.ExecuteTransaction(queryUpdatePaths); // update all paths inside db

            queryUpdatePaths = "";
            string queryTfc = "SELECT File_Name FROM tbl_Tfc;";
            DataTable tableTfc = sqlDB.GetDataTable(queryTfc);
            foreach (DataRow tfcNameRow in tableTfc.Rows)
            {
                string tfcPath = ToString(tfcNameRow,"File_Name");
                string tfcFileName = Path.GetFileName(tfcPath);
                string tfcDirectory = Path.GetDirectoryName(tfcPath);
                string newPath = null;
                if (File.Exists(tfcPath)) // if file already exists then jump to next
                    continue;
                foreach (string defaultPath in defaultPathList) // check if file is present inside default path list
                {
                    if (File.Exists(defaultPath + "\\" + tfcFileName))
                    {
                        newPath = defaultPath + "\\" + tfcFileName;
                        break;
                    }
                }
                if (newPath == null) // if file not found inside default path list
                {
                    openFileDialog.Title = "Select the archive " + tfcFileName;
                    openFileDialog.FileName = tfcFileName;
                    openFileDialog.Filter = tfcFileName + "|" + tfcFileName;
                    if (openFileDialog.ShowDialog() == DialogResult.OK) // directly search the file
                    {
                        newPath = openFileDialog.FileName;
                        defaultPathList.Add(Path.GetDirectoryName(openFileDialog.FileName));
                    }
                    else // if user cancel, then exit the function
                        return false;
                }
                queryUpdatePaths += @"UPDATE tbl_Tfc SET File_Name = '" + newPath + "' WHERE File_Name = '" + tfcPath + "';";
            }
            sqlDB.ExecuteTransaction(queryUpdatePaths); // update all paths inside db

            return true;
        }

        public void buildListFromDB(ToolStripProgressBar pBar)
        {
            textureList = new TextureInfoCollection();
            string queryTex = "SELECT * FROM View_Texture ORDER BY Tex_Name COLLATE NOCASE;";
            DataTable tableTex = sqlDB.GetDataTable(queryTex);

//            string queryTempPcc = "CREATE TEMP TABLE Temp_Pcc_List AS SELECT Tex_Id, File_Name, Tex_Offset FROM tbl_Pcc AS Pcc,tbl_Tex_Pcc WHERE Pcc.Id = tbl_Tex_Pcc.Pcc_Id;";
  //          sqlDB.ExecuteNonQuery(queryTempPcc);

            pBar.Minimum = 0;
            pBar.Value = 0;
            pBar.Step = 1;
            pBar.Maximum = tableTex.Rows.Count;

            foreach (DataRow textureEntry in tableTex.Rows)
            {
                pBar.PerformStep();
                TextureInfo textureInfo = new TextureInfo();

                textureInfo.id = ToString(textureEntry,"Tex_Id");
                textureInfo.name = ToString(textureEntry,"Tex_Name");
                textureInfo.format = ToString(textureEntry,"Format");
                if (ToString(textureEntry,"Size_X") != "" && ToString(textureEntry,"Size_Y") != "")
                {
                    textureInfo.size = new ImageSize(ToUInt(textureEntry,"Size_X"), ToUInt(textureEntry,"Size_Y"));
                }
                if (ToString(textureEntry,"Original_Size_X") != "" && ToString(textureEntry,"Original_Size_Y") != "")
                {
                    textureInfo.originalSize = new ImageSize(ToUInt(textureEntry,"Original_Size_X"), ToUInt(textureEntry,"Original_Size_Y"));
                }
                textureInfo.mipTailBaseIdx = ToInt(textureEntry,"MipTailBaseIdx");
                textureInfo.internalFormatLODBias = ToInt(textureEntry,"LOD_Bias");
                textureInfo.LODGroup = ToString(textureEntry,"LOD_Group");
                textureInfo.LODGroupVal = ToInt(textureEntry, "LOD_Group_Val");
                textureInfo.LODGroupOffset = ToLong(textureEntry, "LOD_Group_Offset");
                textureInfo.tfcFileName = ToString(textureEntry, "Tfc_Name");

                /*textureInfo.pccFileList = new SortedList<string, long>();
                //string queryPcc = "SELECT File_Name, Tex_Offset FROM tbl_Pcc AS Pcc,tbl_Tex_Pcc WHERE Pcc.Id = tbl_Tex_Pcc.Pcc_Id AND  tbl_Tex_Pcc.Tex_Id = '" + textureEntry["Id"] + "';";
                string queryPcc = "SELECT * FROM Temp_Pcc_List WHERE Tex_Id = '" + textureEntry["Id"] + "';";
                DataTable tablePcc = sqlDB.GetDataTable(queryPcc);
                foreach (DataRow pccEntry in tablePcc.Rows)
                {
                    textureInfo.pccFileList.Add(Convert.ToString(pccEntry["File_Name"]), Convert.ToInt64(pccEntry["Tex_Offset"]));
                }

                /*textureInfo.TexDataList = new TextureDataCollection();
                string queryImg = "SELECT * FROM tbl_Image WHERE Texture_Id = '" + textureEntry["Id"] + "';";
                DataTable tableImg = sqlDB.GetDataTable(queryImg);
                foreach (DataRow imgEntry in tableImg.Rows)
                {
                    TextureData textureData =
                        new TextureData(
                            (storage)Convert.ToInt32(imgEntry["Storage_Type"]),
                            new ImageSize(Convert.ToUInt32(imgEntry["Width"]), Convert.ToUInt32(imgEntry["Height"])),
                            Convert.ToInt64(imgEntry["Data_Offset"]),
                            Convert.ToInt64(imgEntry["Pcc_Offset"]),
                            Convert.ToInt32(imgEntry["Compressed_Size"]),
                            Convert.ToInt32(imgEntry["Uncompressed_Size"])
                            );
                    textureInfo.TexDataList.Add(textureData);
                }*/
                textureList.Add(textureInfo);
            }

            string queryPccTex = "SELECT * FROM View_Pcc_List ORDER BY Tex_Id;";
            DataTable tablePccTex = sqlDB.GetDataTable(queryPccTex);
            foreach (DataRow pccTexEntry in tablePccTex.Rows)
            {
                TextureInfo textureInfo = textureList[ToString(pccTexEntry, "Tex_Id")];
                textureInfo.pccFileList.Add(ToString(pccTexEntry, "File_Name"), ToLong(pccTexEntry, "Tex_Offset"));
            }

            string queryImg = "SELECT * FROM tbl_Image;";
            DataTable tableImg = sqlDB.GetDataTable(queryImg);
            foreach (DataRow imgEntry in tableImg.Rows)
            {
                TextureInfo textureInfo = textureList[ToString(imgEntry, "Texture_Id")];
                TextureData textureData =
                    new TextureData(
                        (storage)ToInt(imgEntry, "Storage_Type"),
                        new ImageSize(ToUInt(imgEntry, "Width"), ToUInt(imgEntry, "Height")),
                        ToInt(imgEntry, "Data_Offset"),
                        ToLong(imgEntry, "Pcc_Offset"),
                        ToInt(imgEntry, "Compressed_Size"),
                        ToInt(imgEntry, "Uncompressed_Size")
                        );
                textureData.id = ToString(imgEntry, "Id");
                textureInfo.TexDataList.Add(textureData);
            }

        }

        /*public void newBuildList()
        {
            textureList = new TextureInfoCollection();
            int count = 0;

            string[] fileList = Directory.GetFiles(@"E:\Mass Effect 3\BIOGame\CookedPCConsole", "*.pcc", SearchOption.AllDirectories);
            foreach (string inputPath in fileList)
            {
                PCC.PCCFile pccFile = new PCC.PCCFile(inputPath);
                foreach(PCC.PCCFile.Export export in pccFile.exportList.Where(uobj => uobj.strPackage == "Texture2D"))
                {
                    bool found = false;
                    //if (!textureList.Any(tex => tex.name == export.strName))
                    foreach(TextureInfo tex in textureList)
                    {
                        if (tex.name == export.strName)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        TextureInfo texInfo = new TextureInfo();
                        texInfo.name = export.strName;
                        texInfo.id = count++.ToString();
                        textureList.Add(texInfo);
                    }
                }
            }
        }*/

        // very slow and heavy procedure!!!
        public void buildList(ToolStripProgressBar pBar, ToolStripLabel label)
        {
            FileStream debugStream = new FileStream("debug.txt", FileMode.Create, FileAccess.Write);
            textureList = new TextureInfoCollection();
            uint textureId = 1;
            uint imageId = 1;

            List<Dictionary<String, String>> insertPccList = new List<Dictionary<string, string>>();
            List<Dictionary<String, String>> insertTexList = new List<Dictionary<string, string>>();
            List<Dictionary<String, String>> insertTexPccList = new List<Dictionary<string, string>>();
            List<Dictionary<String, String>> insertImageList = new List<Dictionary<string, string>>();

            // ------------------------- fill the values for every pcc file ------------------------
            string[] fileList = Directory.GetFiles(@"E:\Mass Effect 3\BIOGame\CookedPCConsole", "*.pcc", SearchOption.AllDirectories);

            pBar.Visible = true;
            pBar.Minimum = 0;
            pBar.Value = 0;
            pBar.Step = 1;
            pBar.Maximum = textureList.Count;
            label.Visible = true;

            foreach (string inputPath in fileList)
            {
                pBar.PerformStep();
                label.Text = "Reading " + Path.GetFileName(inputPath);

                int countTex = 0;
                using (var input = File.OpenRead(inputPath))
                {
                    var magic = input.ReadValueU32(Endian.Little);
                    if (magic != 0x9E2A83C1 &&
                        magic.Swap() != 0x9E2A83C1)
                    {
                        throw new FormatException("not a package");
                    }
                    var endian = magic == 0x9E2A83C1 ?
                        Endian.Little : Endian.Big;
                    var encoding = endian == Endian.Little ?
                        Encoding.Unicode : Encoding.BigEndianUnicode;

                    var versionLo = input.ReadValueU16(endian);
                    var versionHi = input.ReadValueU16(endian);

                    if (versionLo != 684 &&
                        versionHi != 194)
                    {
                        throw new FormatException("unsupported version");
                    }

                    input.Seek(4, SeekOrigin.Current);

                    var folderNameLength = input.ReadValueS32(endian);
                    var folderNameByteLength =
                        folderNameLength >= 0 ? folderNameLength : (-folderNameLength * 2);
                    input.Seek(folderNameByteLength, SeekOrigin.Current);

                    var packageFlags = input.ReadValueU32(endian);

                    if ((packageFlags & 8) != 0)
                    {
                        input.Seek(4, SeekOrigin.Current);
                    }

                    var nameCount = input.ReadValueU32(endian);
                    var namesOffset = input.ReadValueU32(endian);
                    var exportCount = input.ReadValueU32(endian);
                    var exportInfosOffset = input.ReadValueU32(endian);
                    var importCount = input.ReadValueU32(endian);
                    var importInfosOffset = input.ReadValueU32(endian);
                    bool isCompressed = true;

                    Stream data;
                    if ((packageFlags & 0x02000000) == 0)
                    {
                        data = input;
                        isCompressed = false;
                    }
                    else
                    {
                        input.Seek(36, SeekOrigin.Current);

                        var generationsCount = input.ReadValueU32(endian);
                        input.Seek(generationsCount * 12, SeekOrigin.Current);

                        input.Seek(20, SeekOrigin.Current);

                        var blockCount = input.ReadValueU32(endian);

                        var blockStream = new BlockStream(input);
                        for (int i = 0; i < blockCount; i++)
                        {
                            var uncompressedOffset = input.ReadValueU32(endian);
                            var uncompressedSize = input.ReadValueU32(endian);
                            var compressedOffset = input.ReadValueU32(endian);
                            var compressedSize = input.ReadValueU32(endian);
                            blockStream.AddBlock(
                                uncompressedOffset, uncompressedSize,
                                compressedOffset, compressedSize);
                        }

                        data = blockStream;
                    }

                    var names = new string[nameCount];

                    var exportInfos = new ExportInfo[exportCount];
                    for (uint i = 0; i < exportCount; i++)
                    {
                        exportInfos[i] = new ExportInfo();
                    }

                    var importInfos = new ImportInfo[importCount];
                    for (uint i = 0; i < importCount; i++)
                    {
                        importInfos[i] = new ImportInfo();
                    }

                    data.Seek(namesOffset, SeekOrigin.Begin);
                    for (uint i = 0; i < nameCount; i++)
                    {
                        var nameLength = data.ReadValueS32(endian);

                        if (nameLength >= 0)
                        {
                            names[i] = data.ReadString(nameLength, true, Encoding.UTF8);
                        }
                        else
                        {
                            names[i] = data.ReadString(-nameLength * 2, true, encoding);
                        }
                        //debugStream.WriteString("" + i.ToString() + ": " + names[i] + "\n");
                    }

                    data.Seek(importInfosOffset, SeekOrigin.Begin);
                    for (uint i = 0; i < importCount; i++)
                    {
                        var importInfo = importInfos[i];

                        var packageNameIndex = data.ReadValueS32(endian);
                        importInfo.PackageName = names[packageNameIndex];

                        data.Seek(12, SeekOrigin.Current);

                        var outerIndex = data.ReadValueS32(endian);
                        importInfo.Outer = GetResource(exportInfos, importInfos, outerIndex);

                        var objectNameIndex = data.ReadValueS32(endian);
                        importInfo.ObjectName = names[objectNameIndex];

                        data.Seek(4, SeekOrigin.Current);
                    }

                    data.Seek(exportInfosOffset, SeekOrigin.Begin);
                    for (uint i = 0; i < exportCount; i++)
                    {
                        var exportInfo = exportInfos[i];

                        exportInfo.PackageName = Path.GetFileNameWithoutExtension(inputPath);

                        var classIndex = data.ReadValueS32(endian);
                        exportInfo.Class = GetResource(exportInfos, importInfos, classIndex);

                        data.Seek(4, SeekOrigin.Current);

                        var outerIndex = data.ReadValueS32(endian);
                        exportInfo.Outer = GetResource(exportInfos, importInfos, outerIndex);

                        var objectNameIndex = data.ReadValueS32(endian);
                        exportInfo.ObjectName = names[objectNameIndex];

                        data.Seek(16, SeekOrigin.Current);

                        exportInfo.DataSize = data.ReadValueU32(endian);
                        exportInfo.DataOffset = data.ReadValueU32(endian);

                        data.Seek(4, SeekOrigin.Current);
                        var count = data.ReadValueU32(endian);
                        data.Seek(count * 4, SeekOrigin.Current);
                        data.Seek(20, SeekOrigin.Current);
                    }

                    for (int i = 0; i < exportInfos.Length; i++)
                    {
                        var exportInfo = exportInfos[i];

                        if (exportInfo.Class == null)
                        {
                            //Console.WriteLine("{0}", exportInfo.FullName);
                            continue;
                        }

                        if (!exportInfo.Class.LocalName.Contains("Texture2D"))
                            continue;
                        countTex++;

                        var texName = exportInfo.ToString();
                        //fullPath = fullPath.Replace(":", "_");

                        // if texture already exists inside list
                        if (textureList.Any(item => item.name == texName))
                        {
                            // if pcc path not exists inside pcc list of texture entry
                            if (!textureList.First(item => item.name == texName).pccFileList.ContainsKey(inputPath))
                                // add pcc path to pcc list of texture entry
                                textureList.First(item => item.name == texName).pccFileList.Add(inputPath, exportInfo.DataOffset);

                            // skip to next export entry
                            continue;
                        }

                        TextureInfo textureEntry = new TextureInfo();
                        textureEntry.name = texName;
                        textureEntry.pccFileList.Add(inputPath, exportInfo.DataOffset);

                        data.Seek(exportInfo.DataOffset + 4, SeekOrigin.Begin);

                        bool exit = false;
                        uint index, origSizeX = 0, origSizeY = 0, sizeX = 0, sizeY = 0;

                        while (!exit)
                        {
                            index = data.ReadValueU32(); // read property index
                            if (index >= names.Length) // if there's an error then throw exception
                                throw new DataMisalignedException();
                            var name = names[index];
                            switch (name)
                            {
                                case "TFCFileGuid": data.Seek(44, SeekOrigin.Current); break;
                                case "TextureFileCacheName":
                                    data.Seek(20, SeekOrigin.Current);
                                    textureEntry.tfcFileName = names[data.ReadValueU32()];
                                    data.Seek(4, SeekOrigin.Current);
                                    break;
                                case "SizeX":
                                    data.Seek(20, SeekOrigin.Current);
                                    sizeX = data.ReadValueU32();
                                    if (sizeY != 0)
                                        textureEntry.size = new ImageSize(sizeX, sizeY);
                                    break;
                                case "SizeY":
                                    data.Seek(20, SeekOrigin.Current);
                                    sizeY = data.ReadValueU32();
                                    if (sizeX != 0)
                                        textureEntry.size = new ImageSize(sizeX, sizeY);
                                    break;
                                case "AddressX": data.Seek(36, SeekOrigin.Current); break;
                                case "AddressY": data.Seek(36, SeekOrigin.Current); break;
                                case "OriginalSizeX":
                                    data.Seek(20, SeekOrigin.Current);
                                    origSizeX = data.ReadValueU32();
                                    if (origSizeY != 0)
                                        textureEntry.originalSize = new ImageSize(origSizeX, origSizeY);
                                    break;
                                case "OriginalSizeY":
                                    data.Seek(20, SeekOrigin.Current);
                                    origSizeY = data.ReadValueU32();
                                    if (origSizeX != 0)
                                        textureEntry.originalSize = new ImageSize(origSizeX, origSizeY);
                                    break;
                                case "MipTailBaseIdx":
                                    data.Seek(20, SeekOrigin.Current);
                                    textureEntry.mipTailBaseIdx = data.ReadValueS32();
                                    break;
                                case "MipGenSettings":
                                    data.Seek(28, SeekOrigin.Current);
                                    textureEntry.mipGenSettings = names[data.ReadValueU32()];
                                    data.Seek(4, SeekOrigin.Current);
                                    break;
                                case "AdjustSaturation":
                                    data.Seek(20, SeekOrigin.Current);
                                    textureEntry.adjustSaturation = data.ReadValueF32();
                                    break;
                                case "AdjustBrightness": // float value
                                    data.Seek(24, SeekOrigin.Current);
                                    break;
                                case "AdjustBrightnessCurve": // float value
                                    data.Seek(24, SeekOrigin.Current);
                                    break;
                                case "AdjustVibrance": // float value
                                    data.Seek(24, SeekOrigin.Current);
                                    break;
                                case "OneBitAlphaThreshold": data.Seek(24, SeekOrigin.Current); break; // int value
                                case "bGlobalForceMipLevelsToBeResident": data.Seek(21, SeekOrigin.Current); break;
                                case "bForceMiplevelsToBeResident": data.Seek(21, SeekOrigin.Current); break;
                                case "bHasBeenLoadedFromPersistentArchive": data.Seek(21, SeekOrigin.Current); break;
                                case "bHasCancelationPending": data.Seek(21, SeekOrigin.Current); break;
                                case "bIsStreamable": data.Seek(21, SeekOrigin.Current); break;
                                case "bIsSourceArtUncompressed": data.Seek(21, SeekOrigin.Current); break;
                                case "bDitherMipMapAlpha": data.Seek(21, SeekOrigin.Current); break;
                                case "bPreserveBorderA": data.Seek(21, SeekOrigin.Current); break;
                                case "bPreserveBorderB": data.Seek(21, SeekOrigin.Current); break;
                                case "bPreserveBorderG": data.Seek(21, SeekOrigin.Current); break;
                                case "bPreserveBorderR": data.Seek(21, SeekOrigin.Current); break;
                                case "CompressionNone": data.Seek(21, SeekOrigin.Current); break;
                                case "CompressionNoMipmaps": data.Seek(21, SeekOrigin.Current); break;
                                case "CompressionNoAlpha": data.Seek(21, SeekOrigin.Current); break;
                                case "CompressionSettings":
                                    data.Seek(28, SeekOrigin.Current);
                                    textureEntry.compressionSettings = names[data.ReadValueU32()];
                                    data.Seek(4, SeekOrigin.Current);
                                    break;
                                case "CompressionFullDynamicRange": data.Seek(21, SeekOrigin.Current); break;
                                case "DeferCompression": data.Seek(21, SeekOrigin.Current); break; // bool value
                                case "Filter": data.Seek(36, SeekOrigin.Current); break;
                                case "Format":
                                    data.Seek(28, SeekOrigin.Current);
                                    textureEntry.format = names[data.ReadValueU32()].Substring(3);
                                    data.Seek(4, SeekOrigin.Current);
                                    break;
                                case "InternalFormatLODBias":
                                    data.Seek(20, SeekOrigin.Current);
                                    textureEntry.internalFormatLODBias = data.ReadValueS32();
                                    break;
                                case "LODBias":
                                    data.Seek(20, SeekOrigin.Current);
                                    textureEntry.internalFormatLODBias = data.ReadValueS32();
                                    break;
                                case "LODGroup":
                                    data.Seek(28, SeekOrigin.Current);
                                    textureEntry.LODGroup = names[data.ReadValueU32()].ToLower();
                                    textureEntry.LODGroupOffset = data.Position - exportInfo.DataOffset;
                                    textureEntry.LODGroupVal = data.ReadValueS32();
                                    break;
                                case "SRGB": data.Seek(21, SeekOrigin.Current); break;
                                case "NeverStream": data.Seek(21, SeekOrigin.Current); break;
                                case "UnpackMin": data.Seek(24, SeekOrigin.Current); break;
                                case "UnpackMax": data.Seek(24, SeekOrigin.Current); break;
                                case "FadeMipMapChannels": data.Seek(136, SeekOrigin.Current); break; // big structure found only in KroInd_MetalTrim_01_Emis_MSK
                                case "None":
                                    data.Seek(4, SeekOrigin.Current);
                                    exit = true;
                                    break;
                                default: exit = true; break;
                            }
                        }
                        /*debugStream.WriteString("data position: 0x" + data.Position.ToString("X8")
                            + ", texture info offset: 0x" + exportInfo.DataOffset + ", texture data size: " + exportInfo.DataSize + "\n");
                        debugStream.Flush();*/

                        //exit if reaches the end of the texture
                        if (data.Position >= exportInfo.DataOffset + exportInfo.DataSize)
                            continue;

                        int mipMaps = data.ReadValueS32();

                        if (mipMaps > textureEntry.mipTailBaseIdx + 2)
                            throw new FormatException();

                        // adding texture values to the insert texture list
                        Dictionary<String, String> dataSQL = new Dictionary<String, String>();
                        dataSQL.Add("Name", textureEntry.name);
                        dataSQL.Add("Format", textureEntry.format);
                        if (textureEntry.size != null)
                        {
                            dataSQL.Add("Size_X", textureEntry.size.width.ToString());
                            dataSQL.Add("Size_Y", textureEntry.size.height.ToString());
                        }
                        if (textureEntry.originalSize != null)
                        {
                            dataSQL.Add("Original_Size_X", textureEntry.originalSize.width.ToString());
                            dataSQL.Add("Original_Size_Y", textureEntry.originalSize.height.ToString());
                        }
                        dataSQL.Add("MipTailBaseIdx", textureEntry.mipTailBaseIdx.ToString());
                        dataSQL.Add("LOD_Bias", textureEntry.internalFormatLODBias.ToString());
                        dataSQL.Add("LOD_Group", textureEntry.LODGroup);
                        dataSQL.Add("LOD_Group_Val", textureEntry.LODGroupVal.ToString());
                        dataSQL.Add("LOD_Group_Offset", textureEntry.LODGroupOffset.ToString());
                        switch (textureEntry.tfcFileName)
                        {
                            case "Textures": dataSQL.Add("Tfc_Id", "1"); break;
                            case "CharTextures": dataSQL.Add("Tfc_Id", "2"); break;
                            case "Lighting": dataSQL.Add("Tfc_Id", "3"); break;
                        }
                        insertTexList.Add(dataSQL);

                        // checking the images
                        int cSize, uSize, offsetTFC;
                        long pccOffset;
                        storage storeVal;
                        ImageSize imgSize;

                        for (int j = 0; j < mipMaps; j++)
                        {
                            pccOffset = data.Position - exportInfo.DataOffset;
                            storeVal = (storage)data.ReadValueS32();
                            uSize = data.ReadValueS32();
                            cSize = data.ReadValueS32();

                            switch (storeVal)
                            {
                                case storage.archive:
                                case storage.dlc:
                                case storage.unused:
                                    offsetTFC = data.ReadValueS32();
                                    break;
                                case storage.local:
                                    if (uSize == cSize)
                                    {
                                        offsetTFC = data.ReadValueS32() - (int)exportInfo.DataOffset;
                                        data.Seek(uSize, SeekOrigin.Current);
                                    }
                                    else
                                        throw new DataMisalignedException();
                                    break;
                                default:
                                    throw new DataMisalignedException();
                            }

                            imgSize = new ImageSize(data.ReadValueU32(), data.ReadValueU32());

                            /*debugStream.WriteString("name: " + fullPath + " " + sizeX + "x" + sizeY + ", in file: " + inputPath + "\n");
                            debugStream.Flush();*/
                            if (!textureEntry.TexDataList.Any(item => item.texSize == imgSize))
                            {
                                TextureData textureData = new TextureData(storeVal, imgSize, offsetTFC, pccOffset, cSize, uSize);
                                textureData.id = imageId++.ToString();
                                textureEntry.TexDataList.Add(textureData);
                            }
                            else
                                break;
                        }
                        /*debugStream.WriteString("num of textures inside " + inputPath + ". " + fullPath + ": " + textureEntry.TexDataList.Count + "\n");
                        debugStream.Flush();*/
                        textureEntry.id = textureId++.ToString();
                        textureList.Add(textureEntry);
                    }

                    // if the pcc file has textures in it then add to the insert pcc list
                    if (countTex > 0)
                    {
                        Dictionary<String, String> dataSQL = new Dictionary<String, String>();
                        dataSQL.Add("File_Name", inputPath);
                        dataSQL.Add("Zlib_Compressed", isCompressed.ToString());
                        dataSQL.Add("Names_Count", nameCount.ToString());
                        dataSQL.Add("Names_Offset", namesOffset.ToString());
                        dataSQL.Add("Export_Info_Count", exportCount.ToString());
                        dataSQL.Add("Export_Info_Offset", exportInfosOffset.ToString());
                        dataSQL.Add("Import_Info_Count", importCount.ToString());
                        dataSQL.Add("Import_Info_Offset", importInfosOffset.ToString());

                        insertPccList.Add(dataSQL);
                    }
                } // end of reading file
            } // end of foreach pcc file

            // db insertion
            //sqlDB.ClearTable("tbl_Pcc");
            Dictionary<string, string> updateSeq = new Dictionary<string,string>();
            /*updateSeq.Add("seq", 0.ToString());
            sqlDB.Update("sqlite_sequence", updateSeq, "name = 'tbl_Pcc'");
            sqlDB.InsertTransaction("tbl_Pcc", insertPccList);*/

            sqlDB.ClearTable("tbl_Texture");
            updateSeq = new Dictionary<string, string>();
            updateSeq.Add("seq", 0.ToString());
            sqlDB.Update("sqlite_sequence", updateSeq, "name = 'tbl_Texture'");
            sqlDB.InsertTransaction("tbl_Texture", insertTexList);

            GC.Collect();

            //sqlDB = new SQLiteDatabase(sqlDBName);
            /*string query;

            pBar.Minimum = 0;
            pBar.Value = 0;
            pBar.Step = 1;
            pBar.Maximum = textureList.Count;

            //filling remaining values
            foreach (TextureInfo textureEntry in textureList)
            {
                pBar.PerformStep();

                Dictionary<String, String> dataSQL = new Dictionary<String, String>();
                query = "select Id ";
                query += "from \"tbl_Texture\" ";
                query += "where Name = \"" + textureEntry.name + "\" LIMIT 1;";
                string texId = sqlDB.ExecuteScalar(query);
                textureEntry.id = texId;

                //fill tbl_Tex_Pcc table
                foreach (KeyValuePair<string, long> kvp in textureEntry.pccFileList)
                {
                    query = "select Id ";
                    query += "from \"tbl_Pcc\" ";
                    query += "where File_Name like \"%" + kvp.Key + "%\" LIMIT 1;";
                    string pccId = sqlDB.ExecuteScalar(query);

                    dataSQL = new Dictionary<String, String>();
                    dataSQL.Add("Tex_Id", texId);
                    dataSQL.Add("Pcc_Id", pccId);
                    dataSQL.Add("Tex_Offset", kvp.Value.ToString());
                    insertTexPccList.Add(dataSQL);
                }

                //fill tbl_Image table
                foreach (TextureData textureData in textureEntry.TexDataList)
                {
                    dataSQL = new Dictionary<String, String>();
                    dataSQL.Add("Width", textureData.texSize.width.ToString());
                    dataSQL.Add("Height", textureData.texSize.height.ToString());
                    dataSQL.Add("Pcc_Offset", textureData.pccOffset.ToString());
                    dataSQL.Add("Data_Offset", textureData.arcOffset.ToString());
                    dataSQL.Add("Compressed_Size", textureData.compressSize.ToString());
                    dataSQL.Add("Uncompressed_Size", textureData.uncompressSize.ToString());
                    dataSQL.Add("Texture_Id", texId);
                    dataSQL.Add("Storage_Type", ((int)textureData.fileStore).ToString());

                    query = "select Id ";
                    query += "from \"tbl_Tfc\" ";
                    query += "where File_Name like \"%\\" + textureEntry.tfcFileName + "%\" LIMIT 1;";
                    string tfcId = sqlDB.ExecuteScalar(query);

                    if (tfcId != "")
                        dataSQL.Add("Tfc_Id", tfcId);
                    insertImageList.Add(dataSQL);
                }
            }
            //MessageBox.Show("Numero relazioni Tex-Pcc: " + insertTexPccList.Count + "\nNumero immagini: " + insertImageList.Count);
            sqlDB.ClearTable("tbl_Tex_Pcc");
            sqlDB.InsertTransaction("tbl_Tex_Pcc", insertTexPccList);
            sqlDB.ClearTable("tbl_Image");
            sqlDB.InsertTransaction("tbl_Image", insertImageList);

            GC.Collect();

            buildListFromDB(pBar);

            //debugStream.Close();*/
        } // end of buildList

        public void extractImage(string imgId, string outputFileName = "")
        {
            SQLiteDatabase sqlDB = new SQLiteDatabase(sqlDBName);
            string query = "select tbl_Texture.Id from tbl_Texture, tbl_Image where Texture_Id = tbl_Texture.Id and tbl_Image.Id = \"" + imgId + "\" limit 1;";
            DataTable imageVal = sqlDB.GetDataTable(query);
            if (imageVal.Rows.Count != 1)
                throw new DataException();
            string texId = ToString(imageVal.Rows[0], "tbl_Texture.Id");
            extractImage(texId, imgId, outputFileName);
        }

        public void extractImage(string texId, string imgId, string outputFileName = "")
        {
            TextureInfo texInfo = textureList[texId];
            TextureData texData = texInfo.TexDataList[imgId];
            MemoryStream rawDataStream = new MemoryStream();
            string archiveFullPath;

            if (outputFileName == "")
            {
                if (texInfo.name != null && texInfo.name != "")
                {
                    outputFileName = texInfo.name + "_" +
                        texInfo.format + "_" +
                        texData.texSize.width + "x" +
                        texData.texSize.height;
                    switch (texInfo.format)
                    {
                        case "V8U8":
                        case "DXT1":
                        case "DXT5": outputFileName += ".dds"; break;
                        case "G8":
                        case "A8R8G8B8": outputFileName += ".tga"; break;
                    }
                }
                else
                    outputFileName = "unknown.bin";
            }

            switch (texData.fileStore)
            {
                //case storage.unused:
                case storage.dlc:
                case storage.archive:
                    FileStream tempStream = new FileStream(texInfo.tfcFileName, FileMode.Open, FileAccess.Read);
                    byte[] buffer = new byte[texData.compressSize];
                    tempStream.Seek(texData.arcOffset, SeekOrigin.Begin);
                    tempStream.Read(buffer,0,buffer.Length);
                    if(texData.fileStore == storage.dlc)
                        rawDataStream.Write(buffer, 0, texData.uncompressSize);
                    else
                        rawDataStream.Write(ZBlock.Decompress(buffer), 0, texData.uncompressSize);
                    tempStream.Close();
                    break;
                case storage.local:
                    archiveFullPath = texInfo.pccFileList.Keys[0];
                    PCCBase pccBase = new PCCBase(archiveFullPath);
                    MemoryStream pccStream = (MemoryStream)pccBase.ToStream();
                    pccStream.Seek((uint)texInfo.pccFileList.Values[0] + texData.arcOffset, SeekOrigin.Begin);
                    rawDataStream.WriteFromStream(pccStream, texData.uncompressSize);
                    pccStream.Close();
                    break;
                default: throw new FormatException();
            }

            FileStream outputStream = new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
            ImageFile imageFile;
            if (texInfo.format == "DXT1" || texInfo.format == "DXT5" || texInfo.format == "V8U8")
            {
                imageFile = new DDS(outputFileName, texData.texSize, texInfo.format, rawDataStream.ToArray());
                outputStream.Write(imageFile.ToArray(), 0, imageFile.ToArray().Length);
            }
            else if (texInfo.format == "A8R8G8B8" || texInfo.format == "G8")
            {
                imageFile = new TGA(outputFileName, texData.texSize, texInfo.format, rawDataStream.ToArray());
                outputStream.Write(imageFile.ToArray(), 0, imageFile.ToArray().Length);
            }
            outputStream.Close();

        }

        public void replaceImage(string texId, string imgId, string inputFileName)
        {
            Dictionary<String, String> updateImg = new Dictionary<string, string>();

            /*string queryImg = "SELECT * FROM tbl_Image WHERE Id = '" + imgId + "';";
            DataTable imgVal = sqlDB.GetDataTable(queryImg);

            string texId = ToString(imgVal.Rows[0],"Texture_Id");*/

            TextureInfo texInfo = textureList[texId];
            TextureData texData = texInfo.TexDataList[imgId];

            ImageFile imgFile;
            string imgExt = Path.GetExtension(inputFileName);
            switch (imgExt)
            {
                case ".dds": imgFile = new DDS(inputFileName); break;
                case ".tga": imgFile = new TGA(inputFileName); break;
                default: throw new FormatException("not known file extension");
            }

            //check for equal format subtype and image size
            if (texData.texSize != imgFile.imgSize)
            {
                MessageBox.Show("Error, images sizes are different:\noriginal: " + texData.texSize + ", new: " + imgFile.imgSize, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (texInfo.format != imgFile.subtype())
            {
                MessageBox.Show("Error, images formats are different:\noriginal: " + texInfo.format + ", new: " + imgFile.subtype(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (texData.fileStore == storage.local)
            {
                if (texData.uncompressSize != imgFile.imgData.Length)
                    throw new FormatException();
                foreach (KeyValuePair<string, long> kvp in texInfo.pccFileList)
                {
                    string pccName = kvp.Key;
                    AmaroK86.MassEffect3.PCCHandler.PCCFile pcc = new AmaroK86.MassEffect3.PCCHandler.PCCFile(pccName);
                    pcc.ReplaceBytes((int)kvp.Value + (int)texData.arcOffset, imgFile.imgData, 0, imgFile.imgData.Length);
                    pcc.Close();
                }
            }
            else if (texData.fileStore == storage.archive || texData.fileStore == storage.unused || texData.fileStore == storage.dlc)
            {
                byte[] compressedImage;
                byte[] essentialImgData = imgFile.resize(); // get rid of unused bytes
                string arcName = texInfo.tfcFileName;

                if (texData.fileStore == storage.dlc) //don't compress if archive isn't compressed
                    compressedImage = essentialImgData;
                else
                    compressedImage = ZBlock.Compress(essentialImgData);

                // writing image data into archive
                FileStream archiveStream = new FileStream(arcName, FileMode.Append, FileAccess.Write);
                long arcOffset = archiveStream.Position;
                archiveStream.Write(compressedImage, 0, compressedImage.Length);
                archiveStream.Close();

                // change the offsets inside every pcc that are related to the image
                foreach (KeyValuePair<string, long> kvp in texInfo.pccFileList)
                {
                    string pccName = kvp.Key;
                    AmaroK86.MassEffect3.PCCHandler.PCCFile pcc = new AmaroK86.MassEffect3.PCCHandler.PCCFile(pccName);
                    pcc.pccStream.Seek(kvp.Value + texData.pccOffset, SeekOrigin.Begin);
                    if (texData.fileStore == storage.unused)
                        pcc.pccStream.WriteValueU32((uint)storage.archive);
                    else
                        pcc.pccStream.WriteValueU32((uint)texData.fileStore);
                    pcc.pccStream.WriteValueS32(essentialImgData.Length); // uncompressed size
                    pcc.pccStream.WriteValueS32(compressedImage.Length);  // compressed size
                    pcc.pccStream.WriteValueU32((uint)arcOffset);         // archive offset
                    pcc.Close();
                }

                //update texture database
                //textureList[texId].TexDataList.Remove(imgSize);
                texData.arcOffset = arcOffset;
                texData.compressSize = compressedImage.Length;
                texData.uncompressSize = essentialImgData.Length;
                texData.fileStore = storage.archive;
                //textureList[texId].TexDataList.Add(new TextureData(texData.fileStore, texData.texSize, arcOffset, texData.pccOffset, compressedImage.Length, essentialImgData.Length));

                updateImg.Add("Data_Offset", arcOffset.ToString());
                updateImg.Add("Compressed_Size", compressedImage.Length.ToString());
                updateImg.Add("Uncompressed_Size", essentialImgData.Length.ToString());
                if (texData.fileStore == storage.unused)
                    updateImg.Add("Storage_Type", storage.archive.ToString("d"));
                if (!sqlDB.Update("tbl_Image", updateImg, "Id = '" + imgId + "'"))
                    throw new Exception();
            }
        }

        private IResource GetResource(ExportInfo[] exportInfos, ImportInfo[] importInfos, int index)
        {
            if (index == 0)
            {
                return null;
            }
            if (index < 0 && -index <= importInfos.Length)
            {
                return importInfos[-index - 1];
            }

            if (index > 0 && index <= exportInfos.Length)
            {
                return exportInfos[index - 1];
            }

            throw new InvalidOperationException();
        }

        public string getMaxImg(string texId)
        {
            TextureInfo textureInfo = textureList[texId];
            uint maxWidth = 0;
            string maxImgId = "";

            foreach (TextureData textureData in textureInfo.TexDataList)
            {
                if (textureData.texSize.width > maxWidth && textureData.compressSize != -1)
                {
                    maxWidth = textureData.texSize.width;
                    maxImgId = textureData.id;
                }
            }

            return maxImgId;
        }

        private int ToInt(DataRow dr, string name)
        {
            return Convert.ToInt32(dr[name]);
        }

        private uint ToUInt(DataRow dr, string name)
        {
            return Convert.ToUInt32(dr[name]);
        }

        private long ToLong(DataRow dr, string name)
        {
            return Convert.ToInt64(dr[name]);
        }

        private string ToString(DataRow dr, string name)
        {
            return Convert.ToString(dr[name]);
        }

        #region XMLFuncs

        public void WriteToXML(string outputFileName)
        {
            if (File.Exists(outputFileName))
                File.Delete(outputFileName);

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;

            if (Path.GetExtension(outputFileName) == "")
                outputFileName = outputFileName + ".xml";

            XmlWriter writer = XmlWriter.Create(outputFileName, settings);
            writer.WriteComment("This file is generated by the program.");
            writer.WriteStartElement("textureList");
            foreach (TextureInfo texEntry in textureList)
            {
                /*if (texEntry.pccFileName.Count == 0)
                    continue;*/
                writer.WriteStartElement("TextureData");
                writer.WriteAttributeString("name", texEntry.name);
                if (texEntry.format != "")
                    writer.WriteElementString("format", texEntry.format);
                if (texEntry.size != null)
                    writer.WriteElementString("size", texEntry.size.ToString());
                if (texEntry.originalSize != null)
                    writer.WriteElementString("originalSize", texEntry.originalSize.ToString());
                if (texEntry.mipTailBaseIdx != 0)
                    writer.WriteElementString("mipTailBaseIdx", texEntry.mipTailBaseIdx.ToString());
                if (texEntry.mipGenSettings != "")
                    writer.WriteElementString("mipGenSettings", texEntry.mipGenSettings);
                if (texEntry.compressionSettings != "")
                    writer.WriteElementString("compressionSettings", texEntry.compressionSettings);
                if (texEntry.adjustSaturation != 0)
                    writer.WriteElementString("adjustSaturation", texEntry.adjustSaturation.ToString());
                if (texEntry.internalFormatLODBias != 0)
                    writer.WriteElementString("internalFormatLODBias", texEntry.internalFormatLODBias.ToString());
                if (texEntry.LODGroup != "")
                    writer.WriteElementString("LODGroup", texEntry.LODGroup);
                if (texEntry.tfcFileName != "")
                    writer.WriteElementString("tfcFileName", texEntry.tfcFileName);
                if (texEntry.pccFileList.Count > 0)
                {
                    writer.WriteStartElement("pccFileList");
                    foreach (KeyValuePair<string, long> kvp in texEntry.pccFileList)
                    {
                        writer.WriteStartElement("pccFileName");
                        writer.WriteAttributeString("name", kvp.Key);
                        writer.WriteElementString("offset", kvp.Value.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                }
                if (texEntry.TexDataList.Count > 0)
                {
                    writer.WriteStartElement("mipMaps");
                    foreach (TextureData texData in texEntry.TexDataList)
                    {
                        writer.WriteStartElement("imgData");
                        writer.WriteElementString("imgFileStore", ((short)texData.fileStore).ToString());
                        writer.WriteElementString("imgArcOffset", texData.arcOffset.ToString());
                        writer.WriteElementString("imgPccOffset", texData.pccOffset.ToString());
                        writer.WriteElementString("imgSize", texData.texSize.ToString());
                        writer.WriteElementString("comprSize", texData.compressSize.ToString());
                        writer.WriteElementString("uncomprSize", texData.uncompressSize.ToString());
                        writer.WriteEndElement();
                    }
                    writer.WriteEndElement();
                }
                writer.WriteEndElement(); //close textureList
            }
            writer.WriteEndDocument();

            writer.Flush();
            writer.Close();
        }

        public void ReadFromXML(string inputFileName)
        {
            if (!File.Exists(inputFileName))
                return;
            if (textureList == null)
                textureList = new TextureInfoCollection();

            string lastElem = "";
            TextureInfo texInfo = new TextureInfo();
            XmlReader reader = XmlReader.Create(inputFileName);

            //FileStream debugStream = new FileStream("debug.txt", FileMode.Create, FileAccess.Write);

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element: // The node is an element.
                        lastElem = reader.Name;
                        if (reader.Name == "TextureData")
                        {
                            texInfo = new TextureInfo();
                            texInfo.name = reader.GetAttribute(0);
                        }
                        if (reader.Name == "pccFileList")
                        {
                            string currentElem = "";
                            string pccFileName = "";
                            long pccOffset = 0;
                            //reads until it gets the end element of pccFileList
                            while (reader.Read() && (reader.NodeType != XmlNodeType.EndElement || reader.Name != "pccFileList"))
                            {
                                switch (reader.NodeType)
                                {
                                    case XmlNodeType.Element:
                                        currentElem = reader.Name;
                                        if (reader.Name == "pccFileName")
                                        {
                                            pccFileName = reader.GetAttribute(0);
                                            pccOffset = 0;
                                        }
                                        break;
                                    case XmlNodeType.Text:
                                        switch (currentElem)
                                        {
                                            case "offset": pccOffset = Convert.ToInt64(reader.Value); break;
                                        }; break;
                                    case XmlNodeType.EndElement:
                                        if (reader.Name == "pccFileName")
                                        {
                                            if(!texInfo.pccFileList.ContainsKey(pccFileName))
                                                texInfo.pccFileList.Add(pccFileName, pccOffset);
                                        }
                                        break;
                                }
                            }
                        }
                        if (reader.Name == "mipMaps")
                        {
                            string currentElem = "";
                            storage fileStore = storage.local;
                            long tfcArcOffset = 0, tfcPccOffset = 0;
                            ImageSize tfcSize = null;
                            int tfcComprSize = 0;
                            int tfcUncomprSize = 0;
                            //reads until it gets the end element of pccFileList
                            while (reader.Read() && (reader.NodeType != XmlNodeType.EndElement || reader.Name != "mipMaps"))
                            {
                                switch (reader.NodeType)
                                {
                                    case XmlNodeType.Element:
                                        currentElem = reader.Name;
                                        if (reader.Name == "imgData")
                                        {
                                            fileStore = storage.local;
                                            tfcArcOffset = 0;
                                            tfcPccOffset = 0;
                                            tfcSize = null;
                                            tfcComprSize = 0;
                                            tfcUncomprSize = 0;
                                        }
                                        break;
                                    case XmlNodeType.Text:
                                        switch (currentElem)
                                        {
                                            case "imgFileStore": fileStore = (storage)Convert.ToInt16(reader.Value); break;
                                            case "imgPccOffset": tfcPccOffset = Convert.ToInt64(reader.Value); break;
                                            case "imgArcOffset": tfcArcOffset = Convert.ToInt64(reader.Value); break;
                                            case "imgSize": tfcSize = ImageSize.stringToSize(reader.Value); break;
                                            case "comprSize": tfcComprSize = Convert.ToInt32(reader.Value); break;
                                            case "uncomprSize": tfcUncomprSize = Convert.ToInt32(reader.Value); break;
                                        }; break;
                                    case XmlNodeType.EndElement:
                                        if (reader.Name == "imgData")
                                        {
                                            texInfo.TexDataList.Add(new TextureData(fileStore, tfcSize, tfcArcOffset, tfcPccOffset, tfcComprSize, tfcUncomprSize));
                                        }
                                        break;
                                }
                            }
                        }
                        break;
                    case XmlNodeType.Text: //Display the text in each element.
                        //debugStream.WriteString(lastElem);
                        switch (lastElem)
                        {
                            case "format": texInfo.format = reader.Value; break;
                            case "size": texInfo.size = ImageSize.stringToSize(reader.Value); break;
                            case "originalSize": texInfo.originalSize = ImageSize.stringToSize(reader.Value); break;
                            case "mipGenSettings": texInfo.mipGenSettings = reader.Value; break;
                            case "compressionSettings": texInfo.compressionSettings = reader.Value; break;
                            case "mipTailBaseIdx": texInfo.mipTailBaseIdx = Convert.ToInt32(reader.Value); break;
                            case "tfcFileName": texInfo.tfcFileName = reader.Value; break;
                            case "adjustSaturation": texInfo.adjustSaturation = Convert.ToSingle(reader.Value); break;
                            case "internalFormatLODBias": texInfo.internalFormatLODBias = Convert.ToInt32(reader.Value); break;
                            case "LODGroup": texInfo.LODGroup = reader.Value; break;
                        }
                        break;
                    case XmlNodeType.EndElement: //Display the end of the element.
                        if (reader.Name == "TextureData")
                            textureList.Add(texInfo);
                        break;
                }
            }
            //debugStream.Close();
        }

        #endregion
    }
}
